package com.xiyuan.smartutils;

import com.xiyuan.smartutils.reflect.Unsafe;

import java.net.Socket;
import java.net.SocketException;

/**
 * Socket相关工具类
 *
 * @version v1.0.0 @author lgz 2017-9-21 新建与整理
 */

public final class Sockets {
    static {
        Unsafe.init();
    }
    private Sockets() {}
    
    /**
     * 设置Socket参数
     *
     * @param socket      Socket
     * @param tcpNoDelay  Enable/disable TCP_NODELAY是否立即响应，即非延迟,不采用Nagle算法
     * @param soTimeoutMs Enable/disable SO_TIMEOUT 读流数据超时时长，单位毫秒，0表示一直阻塞不超时，建议>0
     * @param soLingerS   Enable/disable SO_LINGER 关闭Socket等待时长，即TIME_WAIT时长，单位秒，JAVA默认最大65535，实际还受制于各系统实现的最大值，系统默认2MLS即4分钟(MLS:Maximum Segment Lifetime英文的缩写,中文可以译为报文最大生存时间,默认2分钟)
     */
    public static void setOption(Socket socket, boolean tcpNoDelay, int soTimeoutMs, int soLingerS) {
        try {
            socket.setTcpNoDelay(tcpNoDelay);
            if (soTimeoutMs >= 0) {socket.setSoTimeout(soTimeoutMs);}
            if (soLingerS > 0) {socket.setSoLinger(true, soLingerS);}
            else {socket.setSoLinger(false, 0);}
        }
        catch (SocketException e) {
            throw Asserts.exception("Sockets.setOption{soTimeoutMs:" + soTimeoutMs + ",soLingerS:" + soLingerS + "},SocketException");
        }
    }
    
    /**
     * 设置Socket参数
     *
     * @param socket      Socket
     * @param tcpNoDelay  Enable/disable TCP_NODELAY 是否立即响应，即非延迟,不采用Nagle算法
     * @param soTimeoutMs Enable/disable SO_TIMEOUT 读流数据超时时长，单位毫秒，0表示一直阻塞不超时，建议>0
     * @param soLingerS   Enable/disable SO_LINGER 关闭Socket等待时长，即TIME_WAIT时长，单位秒，JAVA默认最大65535，实际还受制于各系统实现的最大值，系统默认2MLS即4分钟(MLS:Maximum Segment Lifetime英文的缩写,中文可以译为报文最大生存时间,默认2分钟)
     * @param keepAlive   Enable/disable SO_KEEPALIVE 是否检查连接有效性，默认2小时检查基本上没意思，每请求连接时可设置为false，超长连接时可设置为true
     */
    public static void setOption(Socket socket, boolean tcpNoDelay, int soTimeoutMs, int soLingerS, boolean keepAlive) {
        try {
            socket.setTcpNoDelay(tcpNoDelay);
            if (soTimeoutMs >= 0) {socket.setSoTimeout(soTimeoutMs);}
            if (soLingerS > 0) {socket.setSoLinger(true, soLingerS);}
            else {socket.setSoLinger(false, 0);}
            socket.setKeepAlive(keepAlive);
        }
        catch (SocketException e) {
            throw Asserts.exception("Sockets.setOption{soTimeoutMs:" + soTimeoutMs + ",soLingerS:" + soLingerS + "},SocketException");
        }
    }
}
